home *** CD-ROM | disk | FTP | other *** search
- /* $Id: plrender.c,v 1.41 1994/08/25 04:05:36 mjl Exp $
- * $Log: plrender.c,v $
- * Revision 1.41 1994/08/25 04:05:36 mjl
- * Eliminated unnecessary header file inclusion.
- *
- * Revision 1.40 1994/07/12 19:22:49 mjl
- * Small change to ensure that cmap0 palette "sticks" when plot is saved from
- * Tk driver.
- *
- * Revision 1.39 1994/06/30 18:55:48 mjl
- * Minor changes to eliminate gcc -Wall warnings.
- */
-
- /*
- plrender.c
-
- Copyright 1991, 1992, 1993
- Geoffrey Furnish
- Maurice LeBrun
-
- This software may be freely copied, modified and redistributed without
- fee provided that this copyright notice is preserved intact on all
- copies and modified copies.
-
- There is no warranty or other guarantee of fitness of this software.
- It is provided solely "as is". The author(s) disclaim(s) all
- responsibility and liability with respect to this software's usage or
- its effect upon hardware or computer systems.
-
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
- This file contains the code to render a PLPLOT metafile, written by
- the metafile driver, plmeta.c.
- */
-
- char ident[] = "@(#) $Id: plrender.c,v 1.41 1994/08/25 04:05:36 mjl Exp $";
-
- #include "plplotP.h"
- #include "plevent.h"
- #include "metadefs.h"
- #include <ctype.h>
-
- static char *program_name = "plrender";
-
- /* Static function prototypes. */
- /* INDENT OFF */
- /* These handle the command loop */
-
- static void process_next (U_CHAR c);
- static void plr_init (U_CHAR c);
- static void plr_line (U_CHAR c);
- static void plr_eop (U_CHAR c);
- static void plr_bop (U_CHAR c);
- static void plr_state (U_CHAR c);
- static void plr_esc (U_CHAR c);
- static void plresc_fill (void);
- static void plresc_rgb (void);
- static void plresc_ancol (void);
-
- /* Support functions */
-
- static U_CHAR getcommand (void);
- static void ungetcommand (U_CHAR);
- static void get_ncoords (PLFLT *x, PLFLT *y, PLINT n);
- static void NextFamilyFile (U_CHAR *);
- static void ReadPageHeader (void);
- static void plr_KeyEH (PLKey *, void *, int *);
- static void SeekToDisp (long);
- static void SeekOnePage (void);
- static void SeekToNextPage (void);
- static void SeekToCurPage (void);
- static void SeekToPrevPage (void);
- static void SeekTo (FPOS_T);
- static void doseek (FPOS_T);
- static void PageIncr (void);
- static void PageDecr (void);
-
- /* Initialization functions */
-
- static void Init (int, char **);
- static void OpenMetaFile (int *, char **);
- static int ReadFileHeader (void);
- static void Help (void);
- static void Usage (char *);
- static void myHelp (void);
- static void mySyntax (void);
- static void myNotes (void);
-
- /* Option handlers */
-
- static int Opt_h (char *, char *, void *);
- static int Opt_v (char *, char *, void *);
- static int Opt_i (char *, char *, void *);
- static int Opt_b (char *, char *, void *);
- static int Opt_e (char *, char *, void *);
- static int Opt_p (char *, char *, void *);
-
- /* Global variables */
- /* Mode flags for argument parsing */
-
- static int mode_plrender = PL_PARSE_OVERRIDE;
- static int mode_plplot = 0;
- static int mode_showall = 0;
-
- /* Page info */
-
- static PLINT disp_beg=1; /* Where to start plotting */
- static PLINT disp_end=-1; /* Where to stop (0 to disable) */
- static PLINT curdisp; /* Current page number */
- static PLINT cursub; /* Current subpage */
- static PLINT curpage; /* Current plot number */
- static PLINT nsubx; /* subpages in x */
- static PLINT nsuby; /* subpages in y */
- static PLINT target_disp; /* Page we are seeking to */
- static PLINT target_page; /* Plot we are seeking to */
- static PLINT delta; /* Number of pages to go forward/back */
- static PLINT pages; /* Number of pages in file */
-
- static int no_pagelinks; /* Set if metafile doesn't have page links */
- static int end_of_page; /* Set when we're at the end of a page */
- static int seek_mode; /* Set after a seek, before a BOP */
- static int addeof_beg; /* Set when we are counting back from eof */
- static int addeof_end; /* Set when we are counting back from eof */
-
- static FPOS_T prevpage_loc; /* Byte position of previous page header */
- static FPOS_T curpage_loc; /* Byte position of current page header */
- static FPOS_T nextpage_loc; /* Byte position of next page header */
-
- /* File info */
-
- static int input_type; /* 0 for file, 1 for stream */
- static PDFstrm *pdfs; /* PDF stream handle */
- static FILE *MetaFile; /* Actual metafile handle, for seeks etc */
-
- static char BaseName[80] = "", FileName[90] = "";
- static PLINT is_family, member=1;
- static char mf_magic[40], mf_version[40];
-
- /* Dummy vars for reading stuff that is to be thrown away */
-
- static U_CHAR dum_uchar;
- static U_SHORT dum_ushort;
- static float dum_float;
-
- /* Plot dimensions */
-
- static short xmin = 0;
- static short xmax = PLMETA_X_OLD;
- static short ymin = 0;
- static short ymax = PLMETA_Y_OLD;
- static PLINT xlen, ylen;
-
- static float pxlx = PIXEL_RES_X_OLD;
- static float pxly = PIXEL_RES_Y_OLD;
-
- static PLFLT dev_xpmm, dev_ypmm;
- static PLINT dev_xmin, dev_xmax, dev_ymin, dev_ymax, dev_xlen, dev_ylen;
- static PLFLT vpxmin, vpxmax, vpxlen, vpymin, vpymax, vpylen;
-
- /* Miscellaneous */
-
- static U_CHAR c_old, c1;
- static U_SHORT npts;
- static int direction_flag, isanum, at_eop;
- static char num_buffer[20];
- static PLFLT x[PL_MAXPOLY], y[PL_MAXPOLY];
-
- /* Exit codes */
-
- #define EX_SUCCESS 0 /* success! */
- #define EX_ARGSBAD 1 /* invalid args */
- #define EX_BADFILE 2 /* invalid filename or contents */
-
- /*----------------------------------------------------------------------*\
- * Options data structure definition.
- \*----------------------------------------------------------------------*/
-
- static PLOptionTable option_table[] = {
- {
- "showall", /* Turns on invisible options */
- NULL,
- NULL,
- &mode_showall,
- PL_OPT_BOOL | PL_OPT_ENABLED | PL_OPT_INVISIBLE,
- "-showall",
- "Turns on invisible options" },
- {
- "h", /* Help */
- Opt_h,
- NULL,
- NULL,
- PL_OPT_FUNC | PL_OPT_ENABLED,
- "-h",
- "Print out this message" },
- {
- "v", /* Version */
- Opt_v,
- NULL,
- NULL,
- PL_OPT_FUNC | PL_OPT_ENABLED,
- "-v",
- "Print out the plrender version number" },
- {
- "i", /* Input file */
- Opt_i,
- NULL,
- NULL,
- PL_OPT_FUNC | PL_OPT_ENABLED | PL_OPT_ARG,
- "-i name",
- "Input filename" },
- {
- "f", /* Filter option */
- NULL,
- NULL,
- &input_type,
- PL_OPT_BOOL | PL_OPT_ENABLED | PL_OPT_ARG,
- "-f",
- "Filter option -- equivalent to \"-i - -o -\"" },
- {
- "b", /* Beginning page number */
- Opt_b,
- NULL,
- NULL,
- PL_OPT_FUNC | PL_OPT_ENABLED | PL_OPT_ARG,
- "-b number",
- "Beginning page number" },
- {
- "e", /* End page number */
- Opt_e,
- NULL,
- NULL,
- PL_OPT_FUNC | PL_OPT_ENABLED | PL_OPT_ARG,
- "-e number",
- "End page number" },
- {
- "p", /* Specified page only */
- Opt_p,
- NULL,
- NULL,
- PL_OPT_FUNC | PL_OPT_ENABLED | PL_OPT_ARG,
- "-p page",
- "Plot given page only" },
- {
- NULL, /* option */
- NULL, /* handler */
- NULL, /* client data */
- NULL, /* address of variable to set */
- 0, /* mode flag */
- NULL, /* short syntax */
- NULL } /* long syntax */
- };
-
- static char *notes[] = {
- "All parameters must be white-space delimited, and plrender options override",
- "any plplot options of the same name. If the \"-i\" flag is omitted the",
- "filename parameter must come last. Specifying \"-\" for the input or output",
- "filename means use stdin or stdout, respectively. Not all options valid",
- "with all drivers. Please see the man pages for more detail.",
- NULL};
-
- /* INDENT ON */
- /*----------------------------------------------------------------------*\
- * main()
- *
- * plrender -- render a PLPLOT metafile.
- \*----------------------------------------------------------------------*/
-
- int
- main(int argc, char *argv[])
- {
- static U_CHAR c;
-
- /* Initialize */
-
- Init(argc, argv);
-
- /*
- * Read & process metafile commands.
- * If familying is turned on, the end of one member file is just treated as
- * a page break assuming the next member file exists.
- */
- for (;;) {
- c_old = c;
- c = getcommand();
-
- if (c == CLOSE) {
- if (is_family)
- NextFamilyFile(&c);
- if ( ! is_family)
- break;
- }
-
- if ((c == BOP || c == ADVANCE) && curdisp == disp_end)
- break;
-
- process_next(c);
- }
-
- /* Done */
-
- pdf_close(pdfs);
- if (strcmp(mf_version, "1993a") >= 0)
- plspause(0);
-
- plend();
- exit(EX_SUCCESS);
- }
-
- /*----------------------------------------------------------------------*\
- * Process the command loop
- \*----------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------*\
- * process_next()
- *
- * Process a command.
- * Typically plrender issues commands to plplot much like an application
- * program would. This results in a more robust and flexible API. On the
- * other hand, it is sometimes necessary to directly call low-level plplot
- * routines to achieve certain special effects, increase performance, or
- * simplify the code.
- \*----------------------------------------------------------------------*/
-
- static void
- process_next(U_CHAR c)
- {
- switch ((int) c) {
-
- case INITIALIZE:
- plr_init(c);
- break;
-
- case LINE:
- case LINETO:
- case POLYLINE:
- plr_line(c);
- break;
-
- case EOP:
- plr_eop(c);
- break;
-
- case BOP:
- plr_bop(c);
- break;
-
- case CHANGE_STATE:
- plr_state(getcommand());
- break;
-
- case ESCAPE:
- plr_esc(c);
- break;
-
- /* These are all commands that should be absent from current metafiles but */
- /* are recognized here for backward compatibility with old metafiles */
-
- case ADVANCE:
- plr_eop(c);
- plr_bop(c);
- break;
-
- case NEW_WIDTH:
- case NEW_COLOR0:
- case NEW_COLOR1:
- plr_state(c);
- break;
-
- case SWITCH_TO_TEXT:
- case SWITCH_TO_GRAPH:
- break;
-
- default:
- plexit("process_next: Unrecognized command");
- }
- }
-
- /*----------------------------------------------------------------------*\
- * void plr_init()
- *
- * Handle initialization.
- \*----------------------------------------------------------------------*/
-
- static void
- plr_init(U_CHAR c)
- {
- float aspect, dev_aspect, ratio;
-
- dbug_enter("plr_init");
-
- /* Register event handler */
-
- plsKeyEH(plr_KeyEH, NULL);
-
- /* Start up plplot */
-
- plinit();
- plP_gsub(&nsubx, &nsuby, &cursub);
-
- /* Set aspect ratio to the natural ratio of the metafile coordinate system. */
-
- xlen = xmax - xmin;
- ylen = ymax - ymin;
-
- aspect = (ylen / pxly) / (xlen / pxlx);
-
- /* Aspect ratio of output device */
-
- plP_gphy(&dev_xmin, &dev_xmax, &dev_ymin, &dev_ymax);
- plP_gpixmm(&dev_xpmm, &dev_ypmm);
-
- dev_xlen = dev_xmax - dev_xmin;
- dev_ylen = dev_ymax - dev_ymin;
-
- dev_aspect = (dev_ylen / dev_ypmm) / (dev_xlen / dev_xpmm);
-
- if (dev_aspect <= 0.)
- fprintf(stderr, "Aspect ratio error: dev_aspect = %f\n", dev_aspect);
-
- ratio = aspect / dev_aspect;
-
- /* Default relative coordinate space */
-
- vpxlen = 1.0;
- vpylen = 1.0;
- vpxmin = 0.5 - vpxlen / 2.;
- vpymin = 0.5 - vpylen / 2.;
- vpxmax = vpxmin + vpxlen;
- vpymax = vpymin + vpylen;
-
- /*
- * Construct viewport that preserves the aspect ratio of the original device
- * (plmeta output file). Thus you automatically get all physical coordinate
- * plots to come out correctly. Note: this could also be done using the
- * driver interface function plsdimap.
- */
- if (ratio <= 0)
- fprintf(stderr, "Aspect ratio error: ratio = %f\n", ratio);
- else if (ratio < 1)
- vpylen = ratio;
- else
- vpxlen = 1. / ratio;
-
- vpxmin = (1. - vpxlen) / 2.;
- vpxmax = vpxmin + vpxlen;
-
- vpymin = (1. - vpylen) / 2.;
- vpymax = vpymin + vpylen;
-
- /* Seek to first page */
-
- cursub = nsubx*nsuby;
- if (disp_beg > 1) {
- if (no_pagelinks)
- plwarn("plrender: Metafile does not support page seeks");
- else {
- ReadPageHeader();
- SeekToDisp(disp_beg);
- }
- }
- }
-
- /*----------------------------------------------------------------------*\
- * plr_line()
- *
- * Draw a line or polyline.
- * Multiple connected lines (i.e. LINETO's) are collapsed into a polyline.
- \*----------------------------------------------------------------------*/
-
- static void
- plr_line(U_CHAR c)
- {
- npts = 1;
-
- switch ((int) c) {
-
- case LINE:
- get_ncoords(x, y, 1);
-
- case LINETO:
- for (;;) {
- get_ncoords(x + npts, y + npts, 1);
-
- npts++;
- if (npts == PL_MAXPOLY)
- break;
-
- c1 = getcommand();
- if (c1 != LINETO) {
- ungetcommand(c1);
- break;
- }
- }
- break;
-
- case POLYLINE:
- plm_rd( pdf_rd_2bytes(pdfs, &npts) );
- get_ncoords(x, y, npts);
- break;
- }
-
- plline(npts, x, y);
-
- x[0] = x[npts - 1];
- y[0] = y[npts - 1];
- }
-
- /*----------------------------------------------------------------------*\
- * get_ncoords()
- *
- * Read n coordinate vectors.
- \*----------------------------------------------------------------------*/
-
- static void
- get_ncoords(PLFLT *x, PLFLT *y, PLINT n)
- {
- short xs[PL_MAXPOLY], ys[PL_MAXPOLY];
- PLINT i;
-
- plm_rd( pdf_rd_2nbytes(pdfs, (U_SHORT *) xs, n) );
- plm_rd( pdf_rd_2nbytes(pdfs, (U_SHORT *) ys, n) );
-
- for (i = 0; i < n; i++) {
- x[i] = xs[i];
- y[i] = ys[i];
- }
- }
-
- /*----------------------------------------------------------------------*\
- * plr_eop()
- *
- * Handle end of page.
- * Here we run into a bit of difficulty with packed pages -- at the end
- * there is no EOP operation done if the page is only partially full.
- * So I peek ahead to see if the next operation is a CLOSE, and if so,
- * push back the CLOSE and issue an EOP regardless.
- \*----------------------------------------------------------------------*/
-
- static void
- plr_eop(U_CHAR c)
- {
- dbug_enter("plr_eop");
-
- c1 = getcommand();
- ungetcommand(c1);
- if (c1 == CLOSE)
- end_of_page = 1;
-
- if (cursub == nsubx * nsuby)
- end_of_page = 1;
-
- if (end_of_page == 1) {
- at_eop = 1;
- plP_eop();
- at_eop = 0;
- }
- }
-
- /*----------------------------------------------------------------------*\
- * plr_bop()
- *
- * Page/subpage advancement.
- \*----------------------------------------------------------------------*/
-
- static void
- plr_bop(U_CHAR c)
- {
- dbug_enter("plr_bop");
-
- ungetcommand(c);
- ReadPageHeader();
-
- /* Advance and setup the page or subpage */
-
- if (end_of_page) {
- plP_bop();
- end_of_page = 0;
- seek_mode = 0;
- }
-
- plP_ssub(nsubx, nsuby, cursub);
- plP_setsub();
-
- plvpor(vpxmin, vpxmax, vpymin, vpymax);
- plwind((PLFLT) xmin, (PLFLT) xmax, (PLFLT) ymin, (PLFLT) ymax);
- }
-
- /*----------------------------------------------------------------------*\
- * plr_state()
- *
- * Handle change in PLStream state (color, pen width, fill attribute, etc).
- \*----------------------------------------------------------------------*/
-
- static void
- plr_state(U_CHAR op)
- {
- int i;
-
- dbug_enter("plr_state");
-
- switch (op) {
-
- case PLSTATE_WIDTH:{
- U_SHORT width;
-
- plm_rd( pdf_rd_2bytes(pdfs, &width) );
-
- plwid(width);
- break;
- }
-
- case PLSTATE_COLOR0:{
- U_SHORT icol;
- U_CHAR icol0, r, g, b;
-
- if (strcmp(mf_version, "1993a") >= 0) {
- plm_rd( pdf_rd_1byte(pdfs, &icol0) );
-
- if (icol0 == PL_RGB_COLOR) {
- plm_rd( pdf_rd_1byte(pdfs, &r) );
- plm_rd( pdf_rd_1byte(pdfs, &g) );
- plm_rd( pdf_rd_1byte(pdfs, &b) );
- plrgb1(r, g, b);
- }
- else {
- plcol(icol0);
- }
- }
- else {
- plm_rd( pdf_rd_2bytes(pdfs, &icol) );
- plcol(icol);
- }
- break;
- }
-
- case PLSTATE_COLOR1:{
- U_SHORT icol1;
- PLFLT col1;
-
- plm_rd( pdf_rd_2bytes(pdfs, &icol1) );
- col1 = (float) icol1 / (float) plsc->ncol1;
- plcol1(col1);
- break;
- }
-
- case PLSTATE_FILL:{
- signed char patt;
-
- plm_rd( pdf_rd_1byte(pdfs, (U_CHAR *) &patt) );
- plpsty(patt);
- break;
- }
-
- case PLSTATE_CMAP0:{
- U_CHAR ncol0;
-
- plm_rd(pdf_rd_1byte(pdfs, &ncol0));
- plsc->ncol0 = ncol0;
- for (i = 0; i < plsc->ncol0; i++) {
- plm_rd(pdf_rd_1byte(pdfs, &plsc->cmap0[i].r));
- plm_rd(pdf_rd_1byte(pdfs, &plsc->cmap0[i].g));
- plm_rd(pdf_rd_1byte(pdfs, &plsc->cmap0[i].b));
- plsc->cmap0setcol[i] = 1;
- }
- break;
- }
-
- case PLSTATE_CMAP1:{
- U_SHORT ncol1;
-
- plm_rd(pdf_rd_2bytes(pdfs, &ncol1));
- plsc->ncol1 = ncol1;
- for (i = 0; i < plsc->ncol1; i++) {
- plm_rd(pdf_rd_1byte(pdfs, &plsc->cmap1[i].r));
- plm_rd(pdf_rd_1byte(pdfs, &plsc->cmap1[i].g));
- plm_rd(pdf_rd_1byte(pdfs, &plsc->cmap1[i].b));
- }
- plsc->cmap1set = 1;
- break;
- }
- }
- }
-
- /*----------------------------------------------------------------------*\
- * plr_esc()
- *
- * Handle all escape functions.
- \*----------------------------------------------------------------------*/
-
- static void
- plr_esc(U_CHAR c)
- {
- U_CHAR op;
-
- dbug_enter("plr_esc");
-
- plm_rd( pdf_rd_1byte(pdfs, &op) );
-
- switch (op) {
-
- case PLESC_FILL:
- plresc_fill();
- break;
-
- /* These are all commands that should be absent from current metafiles but */
- /* are recognized here for backward compatibility with old metafiles */
-
- case PLESC_SET_RGB:
- plresc_rgb();
- return;
-
- case PLESC_ALLOC_NCOL:
- plresc_ancol();
- return;
-
- case PLESC_SET_LPB:
- plm_rd( pdf_rd_2bytes(pdfs, &dum_ushort) );
- plm_rd( pdf_rd_2bytes(pdfs, &dum_ushort) );
- plm_rd( pdf_rd_2bytes(pdfs, &dum_ushort) );
- plm_rd( pdf_rd_2bytes(pdfs, &dum_ushort) );
- return;
- }
- }
-
- /*----------------------------------------------------------------------*\
- * plresc_fill()
- *
- * Fill polygon described in points pls->dev_x[] and pls->dev_y[].
- \*----------------------------------------------------------------------*/
-
- static void
- plresc_fill(void)
- {
- dbug_enter("plresc_fill");
-
- plm_rd( pdf_rd_2bytes(pdfs, &npts) );
- get_ncoords(x, y, npts);
- plfill(npts, x, y);
- }
-
- /*----------------------------------------------------------------------*\
- * plresc_rgb()
- *
- * Process escape function for RGB color selection.
- * Note that RGB color selection is no longer handled this way by
- * plplot but we must handle it here for old metafiles.
- \*----------------------------------------------------------------------*/
-
- static void
- plresc_rgb(void)
- {
- float red, green, blue;
- U_SHORT ired, igreen, iblue;
-
- dbug_enter("plresc_rgb");
-
- plm_rd( pdf_rd_2bytes(pdfs, &ired) );
- plm_rd( pdf_rd_2bytes(pdfs, &igreen) );
- plm_rd( pdf_rd_2bytes(pdfs, &iblue) );
-
- red = (double) ired / 65535.;
- green = (double) igreen / 65535.;
- blue = (double) iblue / 65535.;
-
- plrgb(red, green, blue);
- }
-
- /*----------------------------------------------------------------------*\
- * plresc_ancol()
- *
- * Process escape function for named color table allocation.
- * OBSOLETE -- just read the info and move on.
- \*----------------------------------------------------------------------*/
-
- static void
- plresc_ancol(void)
- {
- U_CHAR icolor;
- char name[80];
-
- dbug_enter("plresc_ancol");
-
- plm_rd( pdf_rd_1byte(pdfs, &icolor) );
- plm_rd( pdf_rd_header(pdfs, name) );
- }
-
- /*----------------------------------------------------------------------*\
- * Support routines
- \*----------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------*\
- * NextFamilyFile()
- *
- * Start the next family if it exists.
- \*----------------------------------------------------------------------*/
-
- static void
- NextFamilyFile(U_CHAR *c)
- {
- dbug_enter("NextFamilyFile");
-
- (void) fclose(MetaFile);
- member++;
- (void) sprintf(FileName, "%s.%i", BaseName, (int) member);
-
- if ((MetaFile = fopen(FileName, "rb")) == NULL) {
- is_family = 0;
- return;
- }
- if (ReadFileHeader()) {
- is_family = 0;
- return;
- }
- pdfs->file = MetaFile;
-
- /*
- * If the family file was created correctly, the first instruction in the
- * file (after state information) MUST be an INITIALIZE. We throw this
- * away and put a page advance in its place.
- */
-
- *c = getcommand();
- while (*c == CHANGE_STATE) {
- plr_state(getcommand());
- *c = getcommand();
- }
-
- if (*c != INITIALIZE)
- fprintf(stderr,
- "Warning, first instruction in member file not an INIT\n");
- else
- *c = ADVANCE;
- }
-
- /*----------------------------------------------------------------------*\
- * getcommand()
- *
- * Read & return the next command
- \*----------------------------------------------------------------------*/
-
- static U_CHAR
- getcommand(void)
- {
- int c;
-
- c = getc(MetaFile);
- if (c == EOF)
- plexit("getcommand: Unable to read from MetaFile");
-
- return (U_CHAR) c;
- }
-
- /*----------------------------------------------------------------------*\
- * ungetcommand()
- *
- * Push back the last command read.
- \*----------------------------------------------------------------------*/
-
- static void
- ungetcommand(U_CHAR c)
- {
- if (ungetc(c, MetaFile) == EOF)
- plexit("ungetcommand: Unable to push back character");
- }
-
- /*----------------------------------------------------------------------*\
- * plr_KeyEH()
- *
- * Keyboard event handler. For mapping keyboard sequences to commands
- * not usually supported by plplot, such as seeking around in the
- * metafile. Recognized commands:
- *
- * <Backspace> |
- * <Delete> | Back page
- * <Page up> |
- *
- * +<num><CR> Seek forward <num> pages.
- * -<num><CR> Seek backward <num> pages.
- *
- * <num><CR> Seek to page <num>.
- * --<num><CR> Seek to <num> pages before EOF.
- *
- * Both <BS> and <DEL> are recognized for a back-page since the target
- * system may use either as its erase key. <Page Up> is present on some
- * keyboards (different from keypad key).
- *
- * No user data is passed in this case, although a test case is
- * illustrated.
- *
- * Illegal input is ignored.
- \*----------------------------------------------------------------------*/
-
- static void
- plr_KeyEH(PLKey *key, void *user_data, int *p_exit_eventloop)
- {
- char *tst = (char *) user_data;
- int input_num, dun_seek = 0, terminator_seen = 0;
-
- #ifdef DEBUG
- fprintf(stderr, "key->code = %x\n", key->code);
- #endif
-
- /* TEST */
-
- if (tst != NULL) {
- pltext();
- fprintf(stderr, "tst string: %s\n", tst);
- plgra();
- }
-
- /* The rest deals with seeking only; so we return if it is disabled */
-
- if (no_pagelinks || (input_type > 0))
- return;
-
- /* Forward (+) or backward (-) */
-
- if (key->string[0] == '+')
- direction_flag++;
-
- else if (key->string[0] == '-')
- direction_flag--;
-
- /* If a number, store into num_buffer */
-
- if (isdigit(key->string[0])) {
- isanum = TRUE;
- (void) strncat(num_buffer, key->string, (20-strlen(num_buffer)));
- }
-
- /*
- * Seek to specified page, or page advance.
- * Not done until user hits <return>.
- * Need to check for both <LF> and <CR> for portability.
- */
- if (key->code == PLK_Return ||
- key->code == PLK_Linefeed ||
- key->code == PLK_Next)
- {
- terminator_seen = 1;
- if (isanum) {
- input_num = atoi(num_buffer);
- if (input_num == 0) {
- if (strcmp(num_buffer, "0"))
- input_num = -1;
- }
- if (input_num >= 0) {
- if (direction_flag == 0)
- target_disp = input_num;
- else if (direction_flag == 1)
- target_disp = curdisp + input_num;
- else if (direction_flag == -1)
- target_disp = curdisp - input_num;
- else if (direction_flag == -2)
- target_disp = pages - input_num;
-
- SeekToDisp(target_disp);
- dun_seek = 1;
- }
- }
- else {
- target_disp = curdisp + 1;
- SeekToDisp(target_disp);
- dun_seek = 1;
- }
- }
-
- /* Page backward */
-
- if (key->code == PLK_BackSpace ||
- key->code == PLK_Delete ||
- key->code == PLK_Prior)
- {
- terminator_seen = 1;
- target_disp = curdisp - 1;
- SeekToDisp(target_disp);
- dun_seek = 1;
- }
-
- /* Cleanup */
-
- if (terminator_seen) {
- num_buffer[0] = '\0';
- direction_flag = 0;
- isanum = 0;
- key->code = 0;
- }
- if (dun_seek && at_eop)
- *p_exit_eventloop = TRUE;
- }
-
- /*----------------------------------------------------------------------*\
- * SeekToDisp()
- *
- * Seek to 'target_disp' displayed page.
- *
- * Several things combine to make this much harder than one would think.
- * These include: taking packed pages into account, seeking from mid-plot,
- * and multiple contiguous seek events. All in all a disgusting mess.
- *
- * When this routine is called we are probably at the end of a page, but
- * maybe not (e.g. if the user hit <Backspace> or <Return> in the middle
- * of the screen update, and the driver immediately processes the event).
- * Also we might be at the end of the file. So only if we are right
- * before the desired displayed page AND the end of page condition is met,
- * we are done.
- *
- * When reference is made to a displayed (i.e. possibly packed) page, I
- * will use variables with the "disp" tag. For metafile pages, I will
- * use "page". I could have used the word "plot" somewhere but I am
- * reserving that for future uses.
- *
- * To deal with multiple contiguous seek events (e.g. the user hits
- * <Backspace> twice before the renderer has a chance to respond) the
- * "seek_mode" variable was found to be necessary.
- \*----------------------------------------------------------------------*/
-
- static void
- SeekToDisp(long target_disp)
- {
- dbug_enter("SeekToDisp");
-
- /* Determine target_page */
- /* Needs to be the last subpage on the preceding displayed page, */
- /* so we subtract 1 unless the last seek is still active */
-
- if ( ! seek_mode)
- --target_disp;
-
- target_page = target_disp * nsubx * nsuby;
- delta = target_page - curpage;
- seek_mode = 1;
-
- /* Handle special cases first -- none of these require seeks. */
- /* An example of how each condition might arise is given. */
-
- /* <Return> at the end of a page */
-
- if ((delta == 0) && at_eop)
- return;
-
- /* <Return> while drawing the last page */
-
- if ((delta >= 0) && (nextpage_loc == 0))
- return;
-
- /* Anything else requires at least one seek */
-
- #ifdef DEBUG
- fprintf(stderr,
- "Before seek: target_page = %d, curpage = %d, curdisp = %d\n",
- target_page, curpage, curdisp);
- #endif
-
- /* <Return> while drawing any page but the last */
-
- if (delta == 0) {
- SeekToNextPage();
- goto done;
- }
-
- /* Prepare for backward seeks by seeking to the start of the current page */
- /* If on the first page, we're done */
-
- if (delta < 0) {
- SeekToCurPage();
- if (prevpage_loc == 0)
- goto done;
- }
-
- /* Now seek by pages until we arrive at the target page */
-
- while (delta != 0)
- SeekOnePage();
-
- done:
- #ifdef DEBUG
- fprintf(stderr, "After seek: curpage = %d, curdisp = %d, cursub = %d\n",
- curpage, curdisp, cursub);
- #endif
-
- end_of_page = 1;
- return;
- }
-
- /*----------------------------------------------------------------------*\
- * SeekOnePage()
- *
- * Seeks one page in appropriate direction, and updates delta.
- * For out of bounds seeks, just stay on the boundary page (first or last).
- \*----------------------------------------------------------------------*/
-
- static void
- SeekOnePage(void)
- {
- if (delta > 0) {
- if (nextpage_loc == 0) {
- SeekToCurPage();
- delta = 0;
- return;
- }
- SeekToNextPage();
- }
- else {
- if (prevpage_loc == 0) {
- SeekToCurPage();
- delta = 0;
- return;
- }
- SeekToPrevPage();
- }
-
- delta = target_page - curpage;
-
- #ifdef DEBUG
- fprintf(stderr, "Now at page %d, disp %d, delta %d\n",
- curpage, curdisp, delta);
- #endif
- return;
- }
-
- /*----------------------------------------------------------------------*\
- * SeekToCurPage()
- *
- * Seeks to beginning of current page, changing the page counters if
- * we pass a page boundary in the process. Are you sufficiently sick
- * yet? I know I am.
- \*----------------------------------------------------------------------*/
-
- static void
- SeekToCurPage(void)
- {
- FPOS_T loc;
-
- if (pl_fgetpos(MetaFile, &loc))
- plexit("plrender: fgetpos call failed");
-
- if (loc != curpage_loc)
- PageDecr();
-
- SeekTo(curpage_loc);
- }
-
- /*----------------------------------------------------------------------*\
- * SeekToNextPage()
- *
- * Seeks to beginning of next page, changing the page counters if
- * we pass a page boundary in the process.
- \*----------------------------------------------------------------------*/
-
- static void
- SeekToNextPage(void)
- {
- FPOS_T loc;
-
- if (pl_fgetpos(MetaFile, &loc))
- plexit("plrender: fgetpos call failed");
-
- if (loc == curpage_loc)
- PageIncr();
-
- SeekTo(nextpage_loc);
- }
-
- /*----------------------------------------------------------------------*\
- * SeekToPrevPage()
- *
- * Seeks to beginning of previous page, changing page counters to
- * take into account each page header we skip over. Getting sicker
- * all the time..
- \*----------------------------------------------------------------------*/
-
- static void
- SeekToPrevPage(void)
- {
- FPOS_T loc;
-
- if (pl_fgetpos(MetaFile, &loc))
- plexit("plrender: fgetpos call failed");
-
- if (loc != curpage_loc)
- PageDecr();
-
- SeekTo(prevpage_loc);
- PageDecr();
- }
-
- /*----------------------------------------------------------------------*\
- * SeekTo()
- *
- * Seeks to specified location, updating page links.
- \*----------------------------------------------------------------------*/
-
- static void
- SeekTo(FPOS_T loc)
- {
- #ifdef DEBUG
- fprintf(stderr, "Seeking to: %d\n", loc);
- #endif
-
- doseek(loc);
-
- /* Update page links */
-
- ReadPageHeader();
- doseek(curpage_loc);
- PageDecr();
- }
-
- /*----------------------------------------------------------------------*\
- * Utility functions:
- *
- * doseek() Seeks to the specified location in the file.
- * PageIncr() Increments page counters
- * PageDecr() Decrements page counters
- \*----------------------------------------------------------------------*/
-
- static void
- doseek(FPOS_T loc)
- {
- if (pl_fsetpos(MetaFile, &loc))
- plexit("plrender: fsetpos call failed");
- }
-
- static void
- PageDecr(void)
- {
- curpage--;
- cursub--;
- if (cursub < 1) {
- cursub = nsubx * nsuby;
- curdisp--;
- }
- }
-
- static void
- PageIncr(void)
- {
- cursub++;
- curpage++;
- if (cursub > nsubx * nsuby) {
- cursub = 1;
- curdisp++;
- }
- }
-
- /* Yes, finally done with the seek routines.
- "BELIEVE IT!" - John Walker, from "Buckaroo Bonzai" */
-
- /*----------------------------------------------------------------------*\
- * ReadPageHeader()
- *
- * Reads the metafile, processing page header info.
- * Assumes the file pointer is positioned immediately before a PAGE.
- \*----------------------------------------------------------------------*/
-
- static void
- ReadPageHeader(void)
- {
- U_CHAR c;
- U_SHORT page;
- U_LONG prevpage, nextpage;
-
- dbug_enter("ReadPageHeader");
-
- /* Read page header */
-
- if (input_type == 0) {
- if (pl_fgetpos(MetaFile, &curpage_loc))
- plexit("plrender: fgetpos call failed");
- }
-
- c = getcommand();
- if (c != PAGE && c != ADVANCE)
- plexit("plrender: page advance expected; none found");
-
- /* Update page/subpage counters and update page links */
-
- PageIncr();
-
- if (strcmp(mf_version, "1992a") >= 0) {
- if (strcmp(mf_version, "1993a") >= 0) {
- plm_rd( pdf_rd_2bytes(pdfs, &page) );
- plm_rd( pdf_rd_4bytes(pdfs, &prevpage) );
- plm_rd( pdf_rd_4bytes(pdfs, &nextpage) );
- prevpage_loc = prevpage;
- nextpage_loc = nextpage;
- }
- else {
- plm_rd( pdf_rd_2bytes(pdfs, &dum_ushort) );
- plm_rd( pdf_rd_2bytes(pdfs, &dum_ushort) );
- }
- }
-
- #ifdef DEBUG
- fprintf(stderr, "Now at page %d, disp %d\n", curpage, curdisp);
- #endif
- }
-
- /*----------------------------------------------------------------------*\
- * Init()
- *
- * Do initialization for main().
- \*----------------------------------------------------------------------*/
-
- static void
- Init(int argc, char **argv)
- {
- int i, status;
-
- dbug_enter("Init");
-
- /* Process plrender command line options */
-
- status = plParseOpts(&argc, argv, mode_plrender, option_table, Usage);
-
- /*
- * We want the plplot command line options to supercede their possible
- * counterparts in the metafile header. So we defer parsing the
- * rest of the command line until after we process the metafile header.
- */
-
- OpenMetaFile(&argc, argv);
- pdfs = pdf_finit(MetaFile);
-
- /* Read header */
-
- if (ReadFileHeader())
- exit(EX_BADFILE);
-
- /* Other miscellaneous housekeeping */
-
- if (addeof_beg) disp_beg += pages;
- if (addeof_end) disp_end += pages;
-
- plSetInternalOpt("-tcl_cmd", "set plw_create_proc plr_create");
-
- /* Finally, give the rest of the command line to plplot to process. */
-
- status = plParseInternalOpts(&argc, argv, mode_plplot);
-
- /*
- * At this point the only remaining argument in argv should be the program
- * name (which should be first). Anything else is an error. Handle illegal
- * flags first.
- */
-
- for (i = 1; i < argc; i++) {
- if ((argv)[i][0] == '-')
- Usage(argv[i]);
- }
-
- /* These must be extraneous file names */
-
- if (i > 1) {
- fprintf(stderr, "Only one filename argument accepted.\n");
- Usage("");
- }
- }
-
- /*----------------------------------------------------------------------*\
- * OpenMetaFile()
- *
- * Attempts to open the named file.
- * If the output file isn't already determined via the -i or -f flags,
- * we assume it's the last argument in argv[].
- \*----------------------------------------------------------------------*/
-
- static void
- OpenMetaFile(int *p_argc, char **argv)
- {
- char name[70];
-
- dbug_enter("OpenMetaFile");
-
- if ( ! strcmp(FileName, "-"))
- input_type = 1;
-
- if (input_type == 1)
- MetaFile = stdin;
-
- else {
- if (*FileName == '\0') {
- if (*p_argc > 1) {
- strncpy(FileName, argv[*p_argc-1], sizeof(FileName) - 1);
- FileName[sizeof(FileName) - 1] = '\0';
- argv[*p_argc] = NULL;
- (*p_argc)--;
- }
- }
- if (*FileName == '\0') {
- fprintf(stderr, "%s: No filename specified.\n", program_name);
- Usage("");
- exit(EX_ARGSBAD);
- }
-
- /*
- * Try to read named Metafile. The following cases are checked in order:
- * <FileName>
- * <FileName>.1
- * <FileName>.plm
- * <FileName>.plm.1
- */
- #ifdef DEBUG
- fprintf(stderr, "Trying to open metafile %s.\n", FileName);
- #endif
- strncpy(name, FileName, sizeof(name) - 1);
- name[sizeof(name) - 1] = '\0';
-
- if ((MetaFile = fopen(FileName, "rb")) != NULL) {
- return;
- }
-
- (void) sprintf(FileName, "%s.%i", name, (int) member);
- if ((MetaFile = fopen(FileName, "rb")) != NULL) {
- (void) sprintf(BaseName, "%s", name);
- is_family = 1;
- return;
- }
-
- (void) sprintf(FileName, "%s.plm", name);
- if ((MetaFile = fopen(FileName, "rb")) != NULL) {
- return;
- }
-
- (void) sprintf(FileName, "%s.plm.%i", name, (int) member);
- if ((MetaFile = fopen(FileName, "rb")) != NULL) {
- (void) sprintf(BaseName, "%s.plm", name);
- is_family = 1;
- return;
- }
-
- fprintf(stderr, "Unable to open the requested metafile.\n");
- Usage("");
- exit(EX_BADFILE);
- }
- }
-
- /*----------------------------------------------------------------------*\
- * ReadFileHeader()
- *
- * Checks file header. Returns 1 if an error occured.
- \*----------------------------------------------------------------------*/
-
- static int
- ReadFileHeader(void)
- {
- char tag[80];
-
- dbug_enter("ReadFileHeader");
-
- /* Read label field of header to make sure file is a PLPLOT metafile */
-
- plm_rd( pdf_rd_header(pdfs, mf_magic) );
- if (strcmp(mf_magic, PLMETA_HEADER)) {
- fprintf(stderr, "Not a PLPLOT metafile!\n");
- return 1;
- }
-
- /* Read version field of header. We need to check that we can read the
- metafile, in case this is an old version of plrender. */
-
- plm_rd( pdf_rd_header(pdfs, mf_version) );
- if (strcmp(mf_version, PLMETA_VERSION) > 0) {
- fprintf(stderr,
- "Error: incapable of reading metafile version %s.\n", mf_version);
- fprintf(stderr, "Please obtain a newer copy of plrender.\n");
- return 1;
- }
-
- /* Disable page seeking on versions without page links */
-
- if (strcmp(mf_version, "1993a") < 0)
- no_pagelinks=1;
-
- /* Return if metafile older than version 1992a (no tagged info). */
-
- if (strcmp(mf_version, "1992a") < 0) {
- return 0;
- }
-
- /* Read tagged initialization info. */
- /* This is an easy way to guarantee backward compatibility. */
-
- for (;;) {
- plm_rd( pdf_rd_header(pdfs, tag) );
- if (*tag == '\0')
- break;
-
- if ( ! strcmp(tag, "pages")) {
- plm_rd( pdf_rd_2bytes(pdfs, &dum_ushort) );
- pages = dum_ushort;
- continue;
- }
-
- if ( ! strcmp(tag, "xmin")) {
- plm_rd( pdf_rd_2bytes(pdfs, &dum_ushort) );
- xmin = dum_ushort;
- continue;
- }
-
- if ( ! strcmp(tag, "xmax")) {
- plm_rd( pdf_rd_2bytes(pdfs, &dum_ushort) );
- xmax = dum_ushort;
- continue;
- }
-
- if ( ! strcmp(tag, "ymin")) {
- plm_rd( pdf_rd_2bytes(pdfs, &dum_ushort) );
- ymin = dum_ushort;
- continue;
- }
-
- if ( ! strcmp(tag, "ymax")) {
- plm_rd( pdf_rd_2bytes(pdfs, &dum_ushort) );
- ymax = dum_ushort;
- continue;
- }
-
- if ( ! strcmp(tag, "pxlx")) {
- plm_rd( pdf_rd_ieeef(pdfs, &pxlx) );
- continue;
- }
-
- if ( ! strcmp(tag, "pxly")) {
- plm_rd( pdf_rd_ieeef(pdfs, &pxly) );
- continue;
- }
-
- if ( ! strcmp(tag, "width")) {
- plm_rd( pdf_rd_1byte(pdfs, &dum_uchar) );
- plwid(dum_uchar);
- continue;
- }
-
- /* Obsolete tags */
-
- if ( ! strcmp(tag, "orient")) {
- plm_rd( pdf_rd_1byte(pdfs, &dum_uchar) );
- continue;
- }
-
- if ( ! strcmp(tag, "aspect")) {
- plm_rd( pdf_rd_ieeef(pdfs, &dum_float) );
- continue;
- }
-
- fprintf(stderr, "Unrecognized PLPLOT metafile header tag.\n");
- exit(EX_BADFILE);
- }
-
- return 0;
- }
-
- /*----------------------------------------------------------------------*\
- * Help()
- *
- * Print long help message.
- \*----------------------------------------------------------------------*/
-
- static void
- Help(void)
- {
- dbug_enter("Help");
-
- fprintf(stderr,
- "\nUsage:\n %s [%s options] [plplot options] [filename]\n",
- program_name, program_name);
-
- if (mode_showall)
- mode_plplot |= PL_PARSE_SHOWALL;
-
- myHelp();
- plHelp(mode_plplot);
- myNotes();
-
- exit(1);
- }
-
- /*----------------------------------------------------------------------*\
- * myHelp()
- *
- * Print long help message associated with plrender options only.
- \*----------------------------------------------------------------------*/
-
- static void
- myHelp(void)
- {
- PLOptionTable *tab;
-
- fprintf(stderr, "\n%s options:\n", program_name);
- for (tab = option_table; tab->opt; tab++) {
- if ( ! (tab->mode & PL_OPT_ENABLED))
- continue;
-
- if ( ! mode_showall && (tab->mode & PL_OPT_INVISIBLE))
- continue;
-
- if (tab->desc == NULL)
- continue;
-
- if (tab->mode & PL_OPT_INVISIBLE)
- fprintf(stderr, " * %-20s %s\n", tab->syntax, tab->desc);
- else
- fprintf(stderr, " %-20s %s\n", tab->syntax, tab->desc);
- }
- }
-
- /*----------------------------------------------------------------------*\
- * myNotes()
- *
- * Print notes associated with long help message for plrender.
- \*----------------------------------------------------------------------*/
-
- static void
- myNotes(void)
- {
- char **cpp;
-
- putc('\n', stderr);
- for (cpp = notes; *cpp; cpp++) {
- fputs(*cpp, stderr);
- putc('\n', stderr);
- }
- putc('\n', stderr);
- }
-
- /*----------------------------------------------------------------------*\
- * Usage()
- *
- * Print usage & syntax message.
- \*----------------------------------------------------------------------*/
-
- static void
- Usage(char *badOption)
- {
- dbug_enter("Usage");
-
- if (*badOption != '\0')
- fprintf(stderr, "\n%s: bad command line option \"%s\"\r\n",
- program_name, badOption);
-
- fprintf(stderr,
- "\nUsage:\n %s [%s options] [plplot options] [filename]\n",
- program_name, program_name);
-
- if (mode_showall)
- mode_plplot |= PL_PARSE_SHOWALL;
-
- mySyntax();
- plSyntax(mode_plplot);
-
- fprintf(stderr, "\nType %s -h for a full description.\r\n\n",
- program_name);
-
- exit(1);
- }
-
- /*----------------------------------------------------------------------*\
- * mySyntax()
- *
- * Print syntax message appropriate for plrender options only.
- \*----------------------------------------------------------------------*/
-
- static void
- mySyntax(void)
- {
- PLOptionTable *tab;
- int col, len;
-
- fprintf(stderr, "\n%s options:", program_name);
-
- col = 80;
- for (tab = option_table; tab->opt; tab++) {
- if ( ! (tab->mode & PL_OPT_ENABLED))
- continue;
-
- if ( ! mode_showall && (tab->mode & PL_OPT_INVISIBLE))
- continue;
-
- if (tab->syntax == NULL)
- continue;
-
- len = 3 + strlen(tab->syntax); /* space [ string ] */
- if (col + len > 79) {
- fprintf(stderr, "\r\n "); /* 3 spaces */
- col = 3;
- }
- fprintf(stderr, " [%s]", tab->syntax);
- col += len;
- }
- fprintf(stderr, "\r\n");
- }
-
- /*----------------------------------------------------------------------*\
- * Input handlers
- \*----------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------*\
- * Opt_h()
- *
- * Performs appropriate action for option "h".
- \*----------------------------------------------------------------------*/
-
- static int
- Opt_h(char *opt, char *optarg, void *client_data)
- {
- /* Help */
-
- Help();
-
- return 1;
- }
-
- /*----------------------------------------------------------------------*\
- * Opt_v()
- *
- * Performs appropriate action for option "v".
- \*----------------------------------------------------------------------*/
-
- static int
- Opt_v(char *opt, char *optarg, void *client_data)
- {
- /* Version */
-
- fprintf(stderr, "plplot metafile version: %s\n", PLMETA_VERSION);
- fprintf(stderr, "plplot library version: %s\n", PLPLOT_VERSION);
- exit(1);
- return 1; /* This serves a purpose */
- }
-
- /*----------------------------------------------------------------------*\
- * Opt_i()
- *
- * Performs appropriate action for option "i".
- \*----------------------------------------------------------------------*/
-
- static int
- Opt_i(char *opt, char *optarg, void *client_data)
- {
- /* Input file */
-
- strncpy(FileName, optarg, sizeof(FileName) - 1);
- FileName[sizeof(FileName) - 1] = '\0';
-
- return 0;
- }
-
- /*----------------------------------------------------------------------*\
- * Opt_b()
- *
- * Performs appropriate action for option "b".
- \*----------------------------------------------------------------------*/
-
- static int
- Opt_b(char *opt, char *optarg, void *client_data)
- {
- /* Beginning page */
-
- if (*optarg == '-') {
- optarg++;
- addeof_beg = 1;
- }
- disp_beg = atoi(optarg);
-
- return 0;
- }
-
- /*----------------------------------------------------------------------*\
- * Opt_e()
- *
- * Performs appropriate action for option "e".
- \*----------------------------------------------------------------------*/
-
- static int
- Opt_e(char *opt, char *optarg, void *client_data)
- {
- /* Ending page */
-
- if (*optarg == '-') {
- optarg++;
- addeof_end = 1;
- }
- disp_end = atoi(optarg);
-
- return 0;
- }
-
- /*----------------------------------------------------------------------*\
- * Opt_p()
- *
- * Performs appropriate action for option "p".
- \*----------------------------------------------------------------------*/
-
- static int
- Opt_p(char *opt, char *optarg, void *client_data)
- {
- /* Specified page only */
-
- if (*optarg == '-') {
- optarg++;
- addeof_beg = 1;
- addeof_end = 1;
- }
- disp_beg = atoi(optarg);
- disp_end = disp_beg;
-
- return 0;
- }
-